/**
 * @description 获取 URL 中的查询参数
 * @param {string} url - 要解析的 URL
 * @returns {Record<string, string | null>} 返回一个对象，包含查询参数及其对应的值
 *
 * @example
 * // 示例用法
 * const url = 'https://example.com?orderSns=123&orderSn=456';
 * const params = getQueryParams(url);
 * console.log(params.orderSns); // 输出: 123
 */
export const getQueryParams = (url: string): Record<string, string | null> => {
  const params = new URL(url).searchParams
  return [...params.entries()].reduce<Record<string, string | null>>((acc, [key, value]) => {
    acc[key] = value
    return acc
  }, {})
}

/**
 * @description 检查请求头中是否包含 referer 字段
 * @param {Record<string, string | undefined>} headers - 请求头对象，包含所有的请求头字段
 * @throws {Error} 如果请求头中缺少 referer 字段，则抛出错误
 *
 * @example
 * const headers = {
 *   'Content-Type': 'application/json',
 *   'accept': 'application/json',
 *   // 'referer': 'http://example.com' // 可以取消注释来测试有 referer 的情况
 * };
 *
 * try {
 *   validateReferer(headers);
 *   console.log('Referer 存在');
 * } catch (error) {
 *   console.error(error.message); // 输出: 请求头中缺少 referer 字段
 * }
 */
export const validateReferer = (headers: Record<string, string | undefined>): void => {
  const referer = headers['referer']

  if (!referer) {
    throw new Error('请求头中缺少 referer 字段')
  }
}

/**
 * @description 检查一个值是否是 undefined
 * @param {*} value - 要检查的值
 * @returns {boolean} - 如果值是 undefined，返回 true；否则返回 false
 */
export const isUndefined = (value: any) => {
  return typeof value === 'undefined'
}

interface OS {
  isTablet: boolean
  isPhone: boolean
  isAndroid: boolean
  isPc: boolean
  isAlipay: boolean
  isApp: boolean
  isBookInApp: boolean
  isWeChatBrower: boolean
  isInvitePhone: boolean
}

// 判断浏览器类型 暂时区分 安卓 iphone pc 平板
export const os: OS | undefined = (function () {
  const ua = navigator.userAgent
  const isWindowsPhone = /(?:Windows Phone)/.test(ua)
  const isSymbian = /(?:SymbianOS)/.test(ua) || isWindowsPhone
  const isAndroid = /(?:Android)/.test(ua)
  const isFireFox = /(?:Firefox)/.test(ua)
  // const isChrome = /(?:Chrome|CriOS)/.test(ua)
  const isTablet =
    /(?:iPad|PlayBook)/.test(ua) ||
    (isAndroid && !/(?:Mobile)/.test(ua)) ||
    (isFireFox && /(?:Tablet)/.test(ua))
  const isPhone = /(?:iPhone)/.test(ua) && !isTablet
  const isPc = !isPhone && !isAndroid && !isSymbian
  const isAlipay = /(?:Alipay)/.test(ua)
  const isApp = /(?:kukecloudappwebview)/.test(ua)
  const isBookInApp = /(?:kukebook)/.test(ua) // 是否 图书在app内打开
  const isWeChatBrower = /(?:MicroMessenger)/.test(ua) // 是否微信浏览器
  const isInvitePhone = /(?:iPhone|iPad)/.test(ua)

  return {
    isTablet,
    isPhone,
    isAndroid,
    isPc,
    isAlipay,
    isApp,
    isBookInApp,
    isWeChatBrower,
    isInvitePhone
  }
})()

type DebounceFunction<T extends (...args: any[]) => any> = (
  ...args: Parameters<T>
) => ReturnType<T> | undefined

/**
 * @description 防抖
 */
export function debounceFn<T extends (...args: any[]) => any>(
  func: T,
  wait?: number | boolean,
  immediate?: boolean
): DebounceFunction<T> {
  if (typeof func !== 'function') throw new TypeError('func must be a function!')

  if (typeof wait === 'undefined') {
    wait = 600
    immediate = false
  }

  if (typeof wait === 'boolean') {
    immediate = wait
    wait = 600
  }

  if (typeof immediate === 'undefined') {
    immediate = false
  }

  if (typeof wait !== 'number') throw new TypeError('wait must be a number!')

  if (typeof immediate !== 'boolean') throw new TypeError('immediate must be a boolean!')

  let timer: NodeJS.Timeout | null = null
  let result: ReturnType<T> | undefined

  return function proxy(...params: Parameters<T>): ReturnType<T> | undefined {
    // eslint-disable-next-line @typescript-eslint/no-this-alias
    const self = this
    const callNow = !timer && immediate

    if (timer) clearTimeout(timer)

    timer = setTimeout(() => {
      if (!immediate) result = func.apply(self, params)
      timer = null
    }, wait)

    if (callNow) result = func.apply(self, params)

    return result
  }
}
